﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>执行原理</title>
    <script type="text/javascript" src="../Content/highlighter/scripts/shCore.js"></script>
    <script type="text/javascript" src="../Content/highlighter/scripts/shBrushCSharp.js"></script>
    <script type="text/javascript" src="../Content/highlighter/scripts/shBrushXml.js"></script>
    <link type="text/css" rel="stylesheet" href="../Content/highlighter/styles/shCoreDefault.css"/>
    <script type="text/javascript">SyntaxHighlighter.all();</script>
</head>
<body>
    <p>
        我带大家一起走一下NFinal的执行流程.<br />
        当HTTP发送http://localhost/App/IndexController/Index.htm请求时,<br />
        IIS会查看Web.Config中的配置.URL正好符合*.htm这个过滤条件<br />
        <pre class="brush: xml;">
        &lt;add verb="*" path="*.htm" type="NFinal.Handler.HandlerFactory"/>
        </pre>
        于是IIS会在Bin目录下查找具有NFinal.Handler.HandlerFactory的类,<br />
        并调用其中的GetHandler返回Handler对象,然后再调用Handler对象的BeginProcess方法.<br />
    </p>
    <pre class="brush: csharp;">
    /// &lt;summary>
    /// NFinal框架重写的HttpHandlerFactory
    /// &lt;/summary>
    public class HandlerFactory:IHttpHandlerFactory
    {
        /// &lt;summary>
        /// 返回一个用于处理HttpRequest的类
        /// &lt;/summary>
        /// &lt;param name="context">&lt;/param>
        /// &lt;param name="requestType">&lt;/param>
        /// &lt;param name="url">&lt;/param>
        /// &lt;param name="pathTranslated">&lt;/param>
        /// &lt;returns>&lt;/returns>
        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            return new Handler();
        }
        /// &lt;summary>
        /// 释放占用的资源,实际无效果
        /// &lt;/summary>
        /// &lt;param name="handler">&lt;/param>
        public void ReleaseHandler(IHttpHandler handler)
        { 
            
        }
    }
    </pre>
    <p>
        而handler类中有一个BeginProcess方法<br />
    </p>
    <pre class="brush: csharp;">
    public override void BeginProcess(System.Web.HttpContext context)
    {
        try
        {
            //这里调用了Main函数
            Main main = new Main();
            main.Run(context);
                
        }
        catch (Exception ex)
        {
            context.Response.Write("exception eccurs ex info : " + ex.Message);
        }
        finally
        {
            context.Response.End();
            EndProcess();////最后别忘了end  
        }
    }  
    </pre>
    <p>
        Main函数用于理URL,把不同的URL分发给不同的模块.此类位于NFinal根目录下,由生成器生成.
    </p>
    <pre class="brush: csharp;">
    public class Main
    {
        protected string GetString(string val, string de)
        {
            return string.IsNullOrEmpty(val) ? de : val;
        }
        protected string UCFirst(string val)
        {
            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            return cultureInfo.TextInfo.ToTitleCase(val);
        }
		  //第一个是app/第二个是Controller/第三个是Folder/第四个是Controller_Short/第五个是方法名/第六个是参数
        private static Regex reg = new Regex(@"(/[^/\s]+)(((?:/[^/\s]+)*)/([^/\s]+)Controller)/([^/\s.]+)((?:/[^/\s.]+)*)",  RegexOptions.IgnoreCase);
        public void Run(HttpContext context)
        {
			string[] hostName=context.Request.Url.Host.ToString().Split('.');
            string subdomain=hostName.Length==3?hostName[0]:"www";
            string folder = "/Manage";
            string controller = "/Manage/Index";
            string app = "/App";
            string controller_short = "Index";
            string action = "Index";
            string[] parameters = null;
            string url = context.Request.RawUrl;

            NameValueCollection get = new NameValueCollection();
            Match mat= reg.Match(context.Request.Path);
            if (mat.Success)
            {
                app =GetString(mat.Groups[1].Value,app);
                controller = GetString(mat.Groups[2].Value, folder);
                folder =mat.Groups[3].Value;
                controller_short =GetString(mat.Groups[4].Value,controller_short);
                action =GetString(mat.Groups[5].Value,action);
                if(mat.Groups[6].Success)
                {
                    parameters = mat.Groups[6].Value.Split('/');
                    //如果长度为奇数说明正确
                    if((parameters.Length&1)==1)
                    {
                        int count=parameters.Length>>1;
						if (count > 0)
                        {
                            for (int i = 0; i < count; i++)
                            {
                                get.Add(parameters[((i << 1)+1)], parameters[(i << 1) + 2]);
                            }
                        }
                    }
                }

                if (context.Request.Form.Count > 0)
                {
                    for (int i = 0; i < context.Request.Form.Count; i++)
                    {
                        get.Add(context.Request.Form.Keys[i], context.Request.Form[i]);
                    }
                }

				switch (app)
				{
					
                    case "/App":
					{ 
						WebMvc.App.Router router = new WebMvc.App.Router();
                        router.Run(context,subdomain, app, folder, controller, action,get); break;
					}
					
                    default: break;
                }
            }
            else
            {
                context.Response.Write("wrong url");
            }
        }
    }
    </pre>
    <p>
        测测到请求是属于App模块,就去调用此模块下的Router类.<br />
        而Router类的Run方法负责调用具体类下的具体函数,执行输出字符串操作.
    </p>
    <pre class="brush: csharp;">
    public class Router
    {
		private string GetString(string val, string de)
        {
            return string.IsNullOrEmpty(val) ? de : val;
        }
        private string UCFirst(string val)
        {
            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            return cultureInfo.TextInfo.ToTitleCase(val);
        }
        public void Main(System.Web.HttpContext context)
        {
            string module = "index";
            string action = "index";
            string[] pathInfo = null;
            NameValueCollection get = new NameValueCollection();
            if (!string.IsNullOrEmpty(context.Request.PathInfo))
            {
                pathInfo = context.Request.PathInfo.Trim(new char[] { '/' }).Split('/');
                module=UCFirst(GetString(pathInfo[0], module));
                action=GetString(pathInfo[1], action);
                if (pathInfo.Length > 2)
                {
                    for (int i = 2; i < pathInfo.Length; i += 2)
                    {
                        get.Add(pathInfo[i], pathInfo[i + 1]);
                    }
                }
            }
            else
            {
                module =UCFirst(GetString(context.Request.QueryString["m"], module));
                action =GetString(context.Request.QueryString["a"], action);
            }
            
            //Run(context,module,action,get);
        }
        public void Run(System.Web.HttpContext context,string subdomain,string app,string folder,string controller,string action,NameValueCollection get)
        {
			switch (controller)
			{
				
				//relativeName="/Manage/IndexController"
				//RelativeDotName=".Manage.IndexController"
				case "/IndexController":
					{
                        
						switch (action)
						{
							
							case "Index": 
							{
								Web.Default.IndexController.IndexAction control= new Web.Default.IndexController.IndexAction(context.Response.Output);
								
								control._context = context;
								control._subdomain = subdomain;
								control._url=context.Request.RawUrl;
								control._get = get;
								control._app=app;
								control._controller = controller;
                                control._action = action;
								control.Before();
								control.Index();
								control.After();
								break;
							}
							
							default: context.Response.Write("找不到类" + controller + "下的" + action + "方法");context.Response.End(); break;
						}
						break;
					}
				
				//relativeName="/Manage/IndexController"
				//RelativeDotName=".Manage.IndexController"
				case "/SampleController":
					{
                        
						switch (action)
						{
							
							case "Show": 
							{
								Web.Default.SampleController.ShowAction control= new Web.Default.SampleController.ShowAction(context.Response.Output);
								int id=get["id"]==null?5:int.Parse(get["id"]);
								control._context = context;
								control._subdomain = subdomain;
								control._url=context.Request.RawUrl;
								control._get = get;
								control._app=app;
								control._controller = controller;
                                control._action = action;
								control.Before();
								control.Show(id);
								control.After();
								break;
							}
							
							default: context.Response.Write("找不到类" + controller + "下的" + action + "方法");context.Response.End(); break;
						}
						break;
					}
				
				//relativeName="/Manage/IndexController"
				//RelativeDotName=".Manage.IndexController"
				case "/Common/Public":
					{
                        
						switch (action)
						{
							
							case "Success": 
							{
								Web.Default.Common.Public.SuccessAction control= new Web.Default.Common.Public.SuccessAction(context.Response.Output);
								string message=get["message"]==null?null:get["message"];string url=get["url"]==null?null:get["url"];int second=get["second"]==null?0:int.Parse(get["second"]);
								control._context = context;
								control._subdomain = subdomain;
								control._url=context.Request.RawUrl;
								control._get = get;
								control._app=app;
								control._controller = controller;
                                control._action = action;
								control.Before();
								control.Success(message,url,second);
								control.After();
								break;
							}
							
							case "Error": 
							{
								Web.Default.Common.Public.ErrorAction control= new Web.Default.Common.Public.ErrorAction(context.Response.Output);
								string message=get["message"]==null?null:get["message"];string url=get["url"]==null?null:get["url"];int second=get["second"]==null?0:int.Parse(get["second"]);
								control._context = context;
								control._subdomain = subdomain;
								control._url=context.Request.RawUrl;
								control._get = get;
								control._app=app;
								control._controller = controller;
                                control._action = action;
								control.Before();
								control.Error(message,url,second);
								control.After();
								break;
							}
							
							default: context.Response.Write("找不到类" + controller + "下的" + action + "方法");context.Response.End(); break;
						}
						break;
					}
				
				default: context.Response.Write("找不到类" + controller); context.Response.End(); break; 
			}
        }
    }
    </pre>
    <p>
        而最终调用的类是这个样子.
    </p>
    <pre class="brush: csharp;">
    using System;
    using System.Collections.Generic;
    using System.Web;

    namespace WebMvc.App.Web.Default.IndexController
    {
        public class IndexAction  : NFinal.BaseAction
	    {
		    public IndexAction(System.IO.TextWriter tw):base(tw){}
		    public IndexAction(string fileName) : base(fileName) {}
            public void Index()
            {
            
			    Write("&lt;!doctype html>&lt;html>&lt;head>&lt;script src=\"/App/Content/js/jquery-1.11.2.min.js\">&lt;/script>&lt;link href=\"/App/Content/css/frame.css\" type=\"text/css\" rel=\"stylesheet\" />&lt;style type=\"text/css\"> .auto-style1 { width: 140px; } .auto-style2 { width: 197px; } &lt;/style>&lt;/head>&lt;body>");
			    Write("\r\n&lt;header class=\"header\">\r\n    NFinal框架:这是头\r\n&lt;/header>&lt;article> Hello,NFinal! &lt;/article>");
			    Write("\r\n&lt;footer>\r\n     NFinal框架.这是尾\r\n&lt;/footer>&lt;/body>&lt;/html>");
            }
        }
    }
    </pre>
</body>
</html>
